home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 June / EnigmA AMIGA RUN 08 (1996)(G.R. Edizioni)(IT)[!][issue 1996-06][EARSAN CD VII].iso / earcd / utmisc1 / chktex.lha / chktex / Utility.c < prev    next >
C/C++ Source or Header  |  1996-04-30  |  15KB  |  776 lines

  1. /*
  2.  *  ChkTeX v1.4, utility functions.
  3.  *  Copyright (C) 1995-96 Jens T. Berger Thielemann
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *  Contact the author at:
  20.  *              Jens Berger
  21.  *              Spektrumvn. 4
  22.  *              N-0666 Oslo
  23.  *              Norway
  24.  *              E-mail: <jensthi@ifi.uio.no>
  25.  *
  26.  *
  27.  */
  28.  
  29. #include "ChkTeX.h"
  30.  
  31. /***************************** SUPPORT FUNCTIONS ************************/
  32.  
  33.  
  34. /*
  35.  * Copies a string with a maximum length of `len' starting at `pos' in
  36.  * `source' into `dest'.
  37.  * Returns -1 if the pos value is beyond the length of the source value,
  38.  * else NULL.
  39.  */
  40.  
  41.  
  42. #ifndef HAVE_STRMID
  43. WORD strmid(const STRPTR source, STRPTR dest, ULONG pos, LONG len)
  44. {
  45.     STRPTR      Start;
  46.     WORD        Retval = -1;
  47.  
  48.     if(len >= 0)
  49.     {
  50.         if(strlen(source) > pos)
  51.         {
  52.             Start = &source[pos];
  53.  
  54.             while((len-- > 0) && (*dest++ = *Start++))
  55.                 ;
  56.  
  57.             if(len == -1)
  58.                 Retval = 0;
  59.         }
  60.     }
  61.     else
  62.         Retval = 0L;
  63.  
  64.     *dest = 0;
  65.  
  66.     return(Retval);
  67. }
  68. #endif
  69.  
  70.  
  71.  
  72. /*
  73.  * Determine whether a file exists.
  74.  *
  75.  */
  76.  
  77.  
  78. BOOL fexists(STRPTR Filename)
  79. {
  80.     BOOL        Retval = FALSE;
  81.  
  82. #if defined(F_OK) && defined(R_OK) && defined(HAVE_ACCESS)
  83.     Retval = access(Filename, F_OK|R_OK) == 0;
  84. #else
  85.     FILE        *fh;
  86.  
  87.     if(fh = fopen(Filename, "r"))
  88.     {
  89.         Retval = TRUE;
  90.         fclose(fh);
  91.     }
  92. #endif
  93. return(Retval);
  94. }
  95.  
  96.  
  97.  
  98. /*
  99.  * 'Safe' memset() replacement.
  100.  * Just tries to check the parameters, so that the risk of killing
  101.  * innocent memory is lowered.
  102.  * Please note that the `n' parameter now is an signed longword, not
  103.  * an size_t. Won't permit that `n' exceeds BUFLEN, nor negative sizes.
  104.  * Returns `to' if some memset()'ing was done, NULL if not.
  105.  */
  106.  
  107. APTR sfmemset(APTR to, int c, LONG n)
  108. {
  109.     if(to && (n > 0))
  110.     {
  111.         n = min(n, BUFSIZ);
  112.  
  113.         return(memset(to, c, (size_t) n));
  114.     }
  115.     return(NULL);
  116. }
  117.  
  118. /*
  119.  * Concatenates the `File' string to the `Dir' string, leaving the result
  120.  * in the `Dir' buffer. Takes care of inserting `directory' characters;
  121.  * if we've got the strings "/usr/foo" and "bar", we'll get
  122.  * "/usr/foo/bar".
  123.  *
  124.  * Behaviour somewhat controlled by the macros SLASH and DIRCHARS in the
  125.  * .h file.
  126.  *
  127.  */
  128.  
  129. void tackon(STRPTR Dir, const STRPTR File)
  130. {
  131.     UBYTE       EndC;
  132.     ULONG       SLen;
  133.     
  134.     if(Dir && (SLen = strlen(Dir)))
  135.     {
  136.         EndC = Dir[SLen -1];
  137.         ifn(strchr(DIRCHARS, EndC))
  138.         {
  139.             Dir[SLen++] = SLASH;
  140.             Dir[SLen  ] = 0L;
  141.         }
  142.     }
  143.  
  144.     strcat(Dir, File);
  145. }
  146.  
  147.  
  148. /*
  149.  * Quick replace function
  150.  * Replaces every occurrence of a character in a string with another one.
  151.  */
  152.  
  153. void strrep(STRPTR String,      /* String to replace within.    */
  154.             const UBYTE From,   /* Character to search for.     */
  155.             const UBYTE To)     /* Character to put instead.    */
  156. {
  157.     int c;
  158.     while((c = *String++))
  159.     {
  160.         if(c == From)
  161.             String[-1] = To;
  162.     }
  163. }
  164.  
  165.  
  166.  
  167. /*
  168.  * Strips tail and/or front of a string
  169.  * Kills trailing/leading spaces. The macro/function SKIP_STRIP(char c)
  170.  * is used to decide whether a space should be skipped. This function
  171.  * should return TRUE if the character should be skipped, FALSE if not.
  172.  * Returns the string which was passed onto it.
  173.  */
  174.  
  175.  
  176. STRPTR strip(STRPTR str,                /* String to strip */
  177.              const WORDBITS flags)      
  178.     /* One of the following: */
  179.     /* STRP_LFT - Strips leading  blanks */
  180.     /* STRP_RGT - Strips trailing blanks */
  181.     /* STRP_BTH - Strips on both sides   */
  182. {
  183.     STRPTR bufptr = str, nlptr;
  184.     UBYTE c;
  185.     
  186.     if(bufptr && (c = *bufptr))
  187.     {
  188.         if(flags & STRP_LFT)
  189.         {
  190.             if(SKIP_STRIP(c) && c)
  191.             {
  192.                 do
  193.                 {
  194.                     c = *++bufptr;
  195.                 } while(SKIP_STRIP(c) && c);
  196.             }
  197.         }
  198.         
  199.         if(flags & STRP_RGT)
  200.         {
  201.             if(c && *bufptr)
  202.             {
  203.                 nlptr = bufptr;
  204.                 
  205.                 while(*++nlptr);
  206.                 
  207.                 do
  208.                 {
  209.                     nlptr[0] = 0;
  210.                     c = *--nlptr;
  211.                 } while(SKIP_STRIP(c) && c && (nlptr > bufptr));
  212.                 
  213.             }
  214.             else
  215.                 *bufptr = 0;
  216.         }
  217.     }
  218.     return(bufptr);
  219. }
  220.  
  221.  
  222. /*
  223.  * Converts all the chars in the string passed into uppercase.
  224.  */
  225.  
  226. #ifndef HAVE_STRUPR
  227. STRPTR strupr(STRPTR String)
  228. {
  229.     STRPTR      Bufptr;
  230.     UBYTE       TmpC;
  231.  
  232.     for(Bufptr = String;
  233.         (TmpC = *Bufptr);
  234.         Bufptr++)
  235.         *Bufptr = toupper(TmpC);
  236.  
  237.     return(String);
  238. }
  239. #endif
  240.  
  241. /*
  242.  * Returns a duplicate of the string passed.
  243.  */
  244.  
  245. #ifndef HAVE_STRDUP
  246. STRPTR strdup(const STRPTR String)
  247. {
  248.     STRPTR      Retval = NULL;
  249.     size_t      Len;
  250.  
  251.     if(String)
  252.     {
  253.         Len = strlen(String) + 1;
  254.         if((Retval = malloc(Len)))
  255.         {
  256.             memcpy(Retval, String, Len);
  257.         }
  258.     }
  259.  
  260.     return(Retval);
  261. }
  262. #endif
  263.  
  264. #ifndef HAVE_STRCASECMP
  265. int strcasecmp(char* a, char *b)
  266. {
  267.   int aa, bb;
  268.  
  269.   do
  270.   {
  271.       aa = *a++;
  272.       bb = *b++;
  273.   } while(aa && ((aa == bb) || (toupper(aa) == toupper(bb))));
  274.   /* bb != 0 is implicit */
  275.  
  276.   return(toupper(aa) - toupper(bb));
  277. }
  278. #endif
  279.  
  280. /*
  281.  * Not all reallocs are intelligent enough to handle NULL's as
  282.  * parameters. This fixes this.
  283.  */
  284.  
  285. void *saferealloc(void *b, size_t n)
  286. {
  287.   APTR  Retval = NULL;
  288.  
  289.   if(b)
  290.   {
  291.        if(n)
  292.           Retval = realloc(b, n);
  293.        else
  294.           free(b);
  295.   }
  296.   else
  297.       Retval = malloc(n);
  298.  
  299.   return(Retval);
  300. }
  301.  
  302. /*
  303.  * Repeatedly writes the From string over To so that we overwrite Len bytes.
  304.  * Does nothing if passed empty/NULL string.
  305.  */
  306.  
  307. void strwrite (STRPTR To, STRPTR From, ULONG Len)
  308. {
  309.   ULONG i, j;
  310.   ULONG FromLen = strlen(From);
  311.  
  312.   Len = min(Len, BUFSIZ);
  313.  
  314.   if(To && From)
  315.   {
  316.       switch(FromLen)
  317.       {
  318.       case 0:
  319.       break;
  320.       case 1:
  321.       memset(To, *From, Len);
  322.       break;
  323.       default:
  324.       for(i = j = 0;
  325.           i < Len;
  326.           i++, j++)
  327.       {
  328.           if(j >= FromLen)
  329.           j = 0;
  330.           To[i] = From[j];
  331.       }
  332.       }
  333.   }
  334. }
  335.  
  336. /* 
  337.  * Checks whether Cmp comes after Str.
  338.  *
  339.  */
  340.  
  341. int strafter(STRPTR Str, STRPTR Cmp)
  342. {
  343.     return(strncmp(Str, Cmp, strlen(Cmp)));
  344. }
  345.  
  346. /*
  347.  * Checks whether Cmp comes before Str. Returns 0 if so, non-zero if not.
  348.  *
  349.  */
  350.  
  351. int strinfront(STRPTR Str, STRPTR Cmp)
  352. {
  353.     int CmpLen = strlen(Cmp);
  354.     
  355.     if(*Cmp)
  356.     {
  357.     Str++;
  358.     Cmp += CmpLen;
  359.     
  360.     while((*--Cmp == *--Str) && (--CmpLen > 0))
  361.         ;
  362.     return(CmpLen);
  363.     }
  364.     else
  365.     return(1);
  366. }
  367.  
  368. /*************************** WORDLIST HANDLING **************************/
  369.  
  370. /*
  371.  * Inserts a duplicate of `Word' into the `Wordlist' structure. You do thus
  372.  * not need to make a duplicate of `Word' yourself.
  373.  */
  374.  
  375. BOOL InsertWord(const STRPTR Word, struct WordList *WL)
  376. {
  377.     STRPTR      WrdCpy;
  378.  
  379.     if((WrdCpy = strdup(Word)))
  380.     {
  381.         if(StkPush(WrdCpy, &WL->Stack))
  382.         {
  383.             WL->Sorted = FALSE;
  384.             return(TRUE);
  385.         }
  386.         free(WrdCpy);
  387.     }
  388.  
  389.     return(FALSE);
  390. }
  391.  
  392. /*
  393.  * Query whether a `Word' is previously InsertWord()'ed into the WL
  394.  * structure. Does case-sensitive comparison.
  395.  */
  396.  
  397.  
  398. BOOL HasWord(const STRPTR Word, struct WordList *WL)
  399. {
  400.     if(WL && WL->Stack.Used && Word)
  401.     {
  402.         ifn(WL->Sorted)
  403.         {
  404.             qsort(&WL->Stack.Data[0], (size_t) WL->Stack.Used,
  405.                   sizeof(APTR), &str_cmp);
  406.             WL->Sorted = TRUE;
  407.         }
  408.  
  409.         if(bsearch(&Word, &WL->Stack.Data[0], (size_t) WL->Stack.Used,
  410.                    sizeof(APTR), &str_cmp))
  411.             return(TRUE);
  412.     }
  413.     return(FALSE);
  414. }
  415.  
  416.  
  417. int str_cmp(const void *a, const void *b)
  418. {
  419.     return(strcmp(*((STRPTR *) a), *((STRPTR *) b)));
  420. }
  421.  
  422. /************************** GENERIC STACK  ******************************/
  423.  
  424. /*
  425.  * Push something onto a stack. Returns TRUE if successful, else FALSE.
  426.  * Note: You can not push a NULL Data element.
  427.  */
  428.  
  429. BOOL StkPush(const APTR Data, struct Stack *Stack)
  430. {
  431.     ULONG       NewSize;
  432.     APTR        *NewBuf;
  433.  
  434.     if(Data && Stack)
  435.     {
  436.         if(Stack->Used >= Stack->Size)
  437.         {
  438.             NewSize = Stack->Size + MINPUDDLE;
  439.  
  440.             if((NewBuf = saferealloc(Stack->Data,
  441.                 (size_t) NewSize * sizeof(APTR))))
  442.             {
  443.                 Stack->Size = NewSize;
  444.                 Stack->Data = NewBuf;
  445.             }
  446.             else
  447.                 return(FALSE);
  448.         }
  449.  
  450.         Stack->Data[Stack->Used++] = Data;
  451.         return(TRUE);
  452.     }
  453.  
  454.     return(FALSE);
  455. }
  456.  
  457. /*
  458.  * Pops an element from the stack.
  459.  *
  460.  */
  461.  
  462. APTR StkPop(struct Stack *Stack)
  463. {
  464.     APTR    Retval = NULL;
  465.  
  466.     if(Stack && (Stack->Used > 0))
  467.     {
  468.         Retval = Stack->Data[--Stack->Used];
  469.  
  470. #ifdef NO_DIRTY_TRICKS
  471.         {
  472.             APTR        *NewBuf;
  473.  
  474.             if(Stack->Used < (Stack->Size/2))
  475.             {
  476.                 ULONG   NewSize;
  477.                 NewSize = Stack->Size - MINPUDDLE;
  478.                 NewSize = max(NewSize, MINPUDDLE);
  479.  
  480.                 if(NewBuf = saferealloc(Stack->Data,
  481.                    (size_t) NewSize * sizeof(APTR)))
  482.                 {
  483.                     Stack->Size = NewSize;
  484.                     Stack->Data = NewBuf;
  485.                 }
  486.             }
  487.         }
  488. #endif
  489.     }
  490.     return(Retval);
  491. }
  492.  
  493. /*
  494.  * Returns the topmost element of the stack.
  495.  */
  496.  
  497. APTR StkTop(struct Stack *Stack)
  498. {
  499.     if(Stack && (Stack->Used > 0))
  500.         return(Stack->Data[Stack->Used - 1]);
  501.     else
  502.         return(NULL);
  503. }
  504.  
  505. /****************************** INPUT STACK *****************************/
  506.  
  507. BOOL PushFileName(STRPTR Name, struct Stack *stack)
  508. {
  509.     FILE        *fh;
  510.     UBYTE       NameBuf [BUFSIZ];
  511.     ULONG       Counter;
  512.  
  513.     if(Name && stack) 
  514.     {
  515.         for(Counter = 0;
  516.             Counter < TeXInputs.Stack.Used;
  517.             Counter++)
  518.         {
  519.             strcpy(NameBuf, TeXInputs.Stack.Data[Counter]);
  520.             strcat(NameBuf, Name);
  521.             if((fh = fopen(NameBuf, "r")))
  522.                 break;
  523.  
  524.             strcat(NameBuf, ".tex");
  525.             if((fh = fopen(NameBuf, "r")))
  526.                 break;
  527.         }
  528.         ifn(fh = fopen(NameBuf, "r")) {
  529.             PrintPrgErr(pmNoTeXOpen, NameBuf);
  530.             return(FALSE);
  531.         }
  532.         return(PushFile(NameBuf, fh, stack));
  533.     }
  534.     return(FALSE);
  535. }
  536.  
  537.  
  538. BOOL PushFile(STRPTR Name, FILE *fh, struct Stack *stack)
  539. {
  540.     struct FileNode     *fn;
  541.     
  542.     if(Name && fh && stack) 
  543.     {
  544.         if((fn = malloc(sizeof(struct FileNode))))
  545.         {
  546.             if((fn->Name = strdup(Name)))
  547.             {
  548.                 fn->fh = fh;
  549.                 fn->Line = 0L;
  550.                 if(StkPush(fn, stack))
  551.                     return(TRUE);
  552.                 free(fn->Name);
  553.             }
  554.             free(fn);
  555.         }
  556.         PrintPrgErr(pmNoStackMem);
  557.     }
  558.  
  559.     return(FALSE);
  560. }
  561.  
  562. STRPTR FGetsStk(STRPTR Dest, ULONG len, struct Stack *stack)
  563. {
  564.     struct FileNode     *fn;
  565.     STRPTR Retval = NULL;
  566.     
  567.     if((fn = StkTop(stack))) {
  568.         do {
  569.             if((Retval = fgets(Dest, (int) len, fn->fh))) {
  570.                 fn->Line++;
  571.                 break;
  572.             }
  573.             
  574.             fn = StkPop(stack);
  575.             fclose(fn->fh);
  576.             free(fn);
  577.             
  578.         } while(!Retval && (fn = StkTop(stack)));
  579.     }
  580.     
  581.     return(Retval);
  582. }
  583.  
  584. STRPTR CurStkName(struct Stack *stack)
  585. {
  586.     struct FileNode     *fn;
  587.     static
  588.         STRPTR  LastName = "";
  589.  
  590.     if(PseudoInName && (stack->Used <= 1))
  591.       return(PseudoInName);
  592.     else 
  593.     {
  594.         if((fn = StkTop(stack)))
  595.             return(LastName = fn->Name);
  596.         else
  597.             return(LastName);
  598.     }
  599. }
  600.  
  601.  
  602. FILE *CurStkFile(struct Stack *stack)
  603. {
  604.     struct FileNode     *fn;
  605.     
  606.     if((fn = StkTop(stack)))
  607.         return(fn->fh);
  608.     else
  609.         return(NULL);
  610. }
  611.  
  612. ULONG CurStkLine(struct Stack *stack)
  613. {
  614.     struct FileNode     *fn;
  615.     static
  616.         ULONG LastLine = 0L;
  617.     
  618.     if((fn = StkTop(stack)))
  619.         return(LastLine = fn->Line);
  620.     else
  621.         return(LastLine);
  622. }
  623.  
  624.  
  625.  
  626. /************************** CHARACTER STACK ******************************/
  627.  
  628. /*
  629.  * Pushes the character on the stack.
  630.  */
  631.  
  632. BOOL PushChar(const UBYTE c, const ULONG Line,
  633.               const ULONG Column, struct Stack *Stk,
  634.               const STRPTR LineCpy)
  635. {
  636.     UBYTE       Buf[2];
  637.     
  638.     Buf[0] = c; Buf[1] = 0;
  639.     
  640.     return(PushErr( Buf, Line, Column, 1,  LineCpy, Stk)); 
  641. }
  642.  
  643. BOOL PushErr( const STRPTR Data, const ULONG Line,
  644.              const ULONG Column, const ULONG ErrLen,
  645.              const STRPTR LineCpy, struct Stack *Stk)
  646. {
  647.     struct ErrInfo      *ci;
  648.     
  649.     if((ci = malloc(sizeof(struct ErrInfo))))
  650.     {
  651.         if((ci->Data = strdup(Data)))
  652.         {
  653.             ci->File = CurStkName(&InputStack);
  654.             ci->Line = Line;
  655.             ci->ErrLen = ErrLen;
  656.             ci->Column = Column;
  657.             ci->LineBuf = LineCpy;
  658.             
  659.             if(StkPush(ci, Stk))
  660.                 return(TRUE);
  661.         }
  662.         free(ci);
  663.     }
  664.     
  665.     return(FALSE);
  666. }
  667.  
  668.  
  669.  
  670. /*
  671.  * Returns and removes a character from the stack, returns NULL if
  672.  * the stack is empty.
  673.  */
  674.  
  675.  
  676. struct ErrInfo *PopErr(struct Stack *Stack)
  677. {
  678.     return((struct ErrInfo *) StkPop(Stack));
  679. }
  680.  
  681. /*
  682.  * Same as PopChar(), but lets the error alone on the stack.
  683.  */
  684.  
  685.  
  686. struct ErrInfo *TopErr(struct Stack *Stack)
  687. {
  688.     return((struct ErrInfo *) StkTop(Stack));
  689. }
  690.  
  691. /*
  692.  * Free all resources associated with a struct FreeInfo.
  693.  */
  694.  
  695. void FreeErrInfo(struct ErrInfo* ei)
  696. {
  697.     if(ei) {
  698.         if(ei->Data)
  699.             free(ei->Data);
  700.         
  701.         free(ei);
  702.     }
  703. }
  704.  
  705.  
  706. /************************* OPEN/CLOSE COUNTING **************************/
  707.  
  708. /*
  709.  * Returns the index a given bracket (`()[]{}') character has in the
  710.  * BrOrder array. Returns ~0 if the character was not a bracket.
  711.  */
  712.  
  713. LONG BrackIndex(const UBYTE c)
  714. {
  715.     switch(c)
  716.     {
  717.     case '(':   
  718.         return(0);
  719.     case ')':   
  720.         return(1);
  721.     case '[':   
  722.         return(2);
  723.     case ']':   
  724.         return(3);
  725.     case '{':   
  726.         return(4);
  727.     case '}':   
  728.         return(5);
  729.     default:    
  730.         return(~0L);
  731.     }
  732. }
  733.  
  734. /*
  735.  * Counts brackets for you. Give it a bracket, and it will update the
  736.  * corresponding counter.
  737.  */
  738.  
  739. void AddBracket(const UBYTE c)
  740. {
  741.     LONG        Index;
  742.  
  743.     if((Index = BrackIndex(c)) != -1)
  744.         Brackets[Index]++;
  745.     
  746. }
  747.  
  748. /*
  749.  * Returns the character that matches the given bracket, NULL if `c'
  750.  * wasn't a bracket character.
  751.  */
  752.  
  753. UBYTE MatchBracket(const UBYTE c)
  754. {
  755.     ULONG       Index;
  756.     UBYTE       Char = 0;
  757.     
  758.     
  759.     if((Index = BrackIndex(c)) != ~0UL)
  760.         Char = BrOrder[Index ^ 1];
  761.     
  762.     return(Char);
  763. }
  764.  
  765.  
  766.  
  767.  
  768.  
  769.  
  770.  
  771.  
  772.  
  773.  
  774.  
  775.  
  776.